#ifndef CPARTICLE_H
#define CPARTICLE_H

#include <time.h>
#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <vector>
#include <string>
using namespace std;

#include "../Heap/Heap.h"

#define PI atan(1.0)*4


template <typename _TO>	 // _TO -> vector caracteristico
class CParticle {
public:
	typedef double	value_t;
	typedef int		position_t;
	
	typedef vector<position_t>	point_t;
	typedef vector<_TO>		pattern_t;	

	typedef Min<CParticle>			min_t;
	typedef Heap<CParticle,min_t>	heap_t;
//	typedef vector<CParticle*>		heap_t;

	pattern_t	_mass;

	point_t		_position;
	string		_label;
	heap_t		*_heap;
	value_t		_gravity;
	value_t		_theta;
public:
	CParticle (void){
		_gravity = NULL;
		_heap = NULL;
		_theta = NULL;
	}

	template <typename __TO>	 
	friend ostream& operator<< (ostream& out, const CParticle<__TO>& _p){
		out << "[ " ;
		out << "P: " << _p._position[0] << " " << _p._position[1] << ", ";
//		out << "L: " << _p._label << ", ";
		out << "G: " << _p._gravity << ", ";
//		out << "T: " << _p._theta << ", M: " ;
//		for (int i = 0; i < _p._mass.size(); i++)
//			out << _p._mass[i] << " ";
//		out << *(_p._heap) << ",";
		out << "]";
		return out;
	}

	void print_heap (void){
		cout << "[ " ;
		cout << "P: " << _position[0] << " " << _position[1] << ", ";
		cout << *(_heap) << ",";
		cout << "]";
	}

	void set_gravity(CParticle _p){
		for (int i = 0; i < _mass.size(); i++)
			_gravity += (_mass[i] - _p._mass[i]) * (_mass[i] - _p._mass[i]);
		_gravity = sqrt(_gravity);
	}

	bool operator> (const CParticle &_p){
		return _gravity > _p._gravity;
	}
	
	bool operator< (const CParticle &_p){
		return _gravity < _p._gravity;
	}

	void init_heap(void){
		_heap = new heap_t();
		_heap->insertar(*this);
	}

	void evolution (CParticle*** &_map, int _limit){		
		do {		
			_theta = rand() % 360;
			double radians = PI * _theta / 180;
			int nx = floor(cos(radians) + .5);
			int ny = floor(sin(radians) + .5);

			if (_position[0] + nx > -1 && _position[0] + nx < _limit)
			{
				if(_position[1] + ny > -1 && _position[1] + ny < _limit)
				{
					if (_map[_position[0] + nx][_position[1] + ny] != NULL)
					{
						if (_map[_position[0] + nx][_position[1] + ny]->_heap == NULL)
						{
							_map[_position[0] + nx][_position[1] + ny]->set_gravity(*this);
							(*_heap) << *(_map[_position[0] + nx][_position[1] + ny]);
							CParticle* temp =	this;
							_map[_position[0]][_position[1]] = NULL;
							temp->_position[0] += nx;
							temp->_position[1] += ny;
							_map[temp->_position[0]][temp->_position[1]] = temp;
						}
					} else {
					CParticle* temp =	this;
					_map[_position[0]][_position[1]] = NULL;
					temp->_position[0] += nx;
					temp->_position[1] += ny;
					_map[temp->_position[0]][temp->_position[1]] = temp;
					}
					break;
				}
			}
		} while(true);
	}

};

#endif // CPARTICLE_H